package com.gzx.plugin.tjzy.core.utils.crypter;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Setter;

import java.util.Objects;
import java.util.function.Function;

/**
 * 密文对象及其加解密逻辑封装器，
 * 实现懒加解密
 */
public class CiphertextWrapper implements Ciphertext, Crypter {
    @Setter
    protected String raw;
    @Setter
    protected String enc;
    @Setter
    protected String mask;

    /**
     * 加密器，
     * 明文 -> 密文
     */
    @Setter(onMethod_ = @JsonIgnore)
    protected Function<String, String> encryptor = ObjectUtil::self;
    /**
     * 解密器，
     * 密文 -> 明文
     */
    @Setter(onMethod_ = @JsonIgnore)
    protected Function<String, String> decryptor = ObjectUtil::self;
    /**
     * 脱敏器，
     * 明文 -> 脱敏后的明文
     */
    @Setter(onMethod_ = @JsonIgnore)
    protected Function<String, String> masker = ObjectUtil::self;

    @JsonIgnore
    public void setCiphertext(Ciphertext ciphertext) {
        if (ciphertext instanceof CiphertextWrapper wrapper) {
            this.raw = wrapper.raw;
            this.enc = wrapper.enc;
            this.mask = wrapper.mask;
        } else {
            this.raw = ciphertext.getRaw();
            this.enc = ciphertext.getEnc();
            this.mask = ciphertext.getMask();
        }
    }

    public CiphertextWrapper copyOf(Ciphertext ciphertext) {
        CiphertextWrapper wrapper = new CiphertextWrapper();
        wrapper.setCiphertext(ciphertext);
        wrapper.encryptor = this.encryptor;
        wrapper.decryptor = this.decryptor;
        wrapper.masker = this.masker;
        return wrapper;
    }

    @Override
    public Ciphertext crypt(Ciphertext ciphertext) {
        return copyOf(ciphertext);
    }

    @Override
    public synchronized String getRaw() {
        if (Objects.isNull(raw) && Objects.nonNull(enc)) {
            raw = decryptor.apply(enc);
        }
        return raw;
    }

    @Override
    public synchronized String getEnc() {
        if (Objects.isNull(enc) && Objects.nonNull(raw)) {
            enc = encryptor.apply(raw);
        }
        return enc;
    }

    @Override
    public synchronized String getMask() {
        if (Objects.isNull(mask)) {
            mask = ObjectUtil.notNullAnd(getRaw(), masker);
        }
        return mask;
    }

    public static CiphertextWrapper wrap(Ciphertext ciphertext) {
        CiphertextWrapper wrapper = new CiphertextWrapper();
        wrapper.setCiphertext(ciphertext);
        return wrapper;
    }

    @Override
    public boolean isEmpty() {
        return Objects.isNull(raw) && Objects.isNull(enc);
    }
}
